/**
 * 全局错误处理工具
 * @author Wu.Liang
 * @date 2025-01-30
 */

/**
 * 初始化全局错误处理
 */
export function initGlobalErrorHandler(): void {
  // 处理未捕获的JavaScript错误
  window.addEventListener('error', (event) => {
    handleError(event.error || event.message, event.filename, event.lineno, event.colno)
  })

  // 处理未处理的Promise拒绝
  window.addEventListener('unhandledrejection', (event) => {
    handleError(event.reason, 'Promise', 0, 0)
  })

  // 处理Vue错误
  if (window.Vue) {
    window.Vue.config.errorHandler = (error, vm, info) => {
      handleVueError(error, vm, info)
    }
  }
}

/**
 * 处理一般错误
 */
function handleError(error: Error | string, filename?: string, lineno?: number, colno?: number): void {
  const errorInfo = {
    message: typeof error === 'string' ? error : error.message,
    stack: typeof error === 'string' ? '' : error.stack,
    filename,
    lineno,
    colno,
    timestamp: new Date().toISOString(),
    userAgent: navigator.userAgent,
    url: window.location.href
  }

  // 检查是否是getBoundingClientRect相关错误
  if (isGetBoundingClientRectError(errorInfo.message)) {
    handleGetBoundingClientRectError(errorInfo)
    return
  }

  // 检查是否是Element Plus相关错误
  if (isElementPlusError(errorInfo.message)) {
    handleElementPlusError(errorInfo)
    return
  }

  // 记录错误到控制台
  console.error('全局错误:', errorInfo)

  // 在生产环境中，可以发送错误到服务器
  if (process.env.NODE_ENV === 'production') {
    // sendErrorToServer(errorInfo)
  }
}

/**
 * 处理Vue错误
 */
function handleVueError(error: Error, vm: any, info: string): void {
  const errorInfo = {
    message: error.message,
    stack: error.stack,
    info,
    componentName: vm?.$options?.name || 'Unknown',
    timestamp: new Date().toISOString(),
    userAgent: navigator.userAgent,
    url: window.location.href
  }

  // 检查是否是getBoundingClientRect相关错误
  if (isGetBoundingClientRectError(errorInfo.message)) {
    handleGetBoundingClientRectError(errorInfo)
    return
  }

  console.error('Vue错误:', errorInfo)
}

/**
 * 检查是否是getBoundingClientRect相关错误
 */
function isGetBoundingClientRectError(message: string): boolean {
  return message.includes('getBoundingClientRect') || 
         message.includes('getBoundingClientRect is not a function') ||
         message.includes('Cannot read properties of null (reading \'getAttribute\')') ||
         message.includes('getAttribute')
}

/**
 * 检查是否是Element Plus相关错误
 */
function isElementPlusError(message: string): boolean {
  return message.includes('element-plus') || 
         message.includes('El') ||
         message.includes('Invalid prop')
}

/**
 * 处理getBoundingClientRect错误
 */
function handleGetBoundingClientRectError(errorInfo: any): void {
  console.warn('检测到getBoundingClientRect错误，这通常是由于DOM元素未准备好导致的:', errorInfo)

  // 尝试延迟执行相关操作
  setTimeout(() => {
    console.log('尝试重新初始化相关组件...')
    // 这里可以触发组件重新渲染或重新初始化
  }, 100)
}

/**
 * 处理Element Plus错误
 */
function handleElementPlusError(errorInfo: any): void {
  console.warn('检测到Element Plus相关错误:', errorInfo)

  // 检查是否是类型错误
  if (errorInfo.message.includes('Invalid prop')) {
    console.warn('Element Plus组件类型错误，请检查props类型定义')
  }
}

/**
 * 安全的DOM操作包装器
 */
export function safeDOMOperation<T>(operation: () => T, fallback?: T): T | undefined {
  try {
    return operation()
  } catch (error) {
    if (error instanceof Error && isGetBoundingClientRectError(error.message)) {
      console.warn('DOM操作失败，使用fallback值:', error.message)
      return fallback
    }
    throw error
  }
}

/**
 * 延迟执行DOM操作
 */
export function delayDOMOperation<T>(operation: () => T, delay: number = 100): Promise<T> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        const result = operation()
        resolve(result)
      } catch (error) {
        reject(error)
      }
    }, delay)
  })
}

/**
 * 重试DOM操作
 */
export async function retryDOMOperation<T>(
  operation: () => T, 
  maxRetries: number = 3, 
  delay: number = 100
): Promise<T> {
  let lastError: Error | null = null

  for (let i = 0; i < maxRetries; i++) {
    try {
      return operation()
    } catch (error) {
      lastError = error as Error
      
      if (isGetBoundingClientRectError(lastError.message)) {
        console.warn(`DOM操作失败，第${i + 1}次重试...`)
        await new Promise(resolve => setTimeout(resolve, delay))
        continue
      }
      
      throw error
    }
  }

  throw lastError || new Error('DOM操作重试失败')
}

// 声明全局Vue类型
declare global {
  interface Window {
    Vue?: {
      config: {
        errorHandler?: (error: Error, vm: any, info: string) => void
      }
    }
  }
} 